package com.leo.chapter05;

import com.leo.anno.LaunderThrowable;

import java.util.Map;
import java.util.concurrent.*;

/**
 * 相对完美了
 *  解决了 复合操作 造成的不安全问题
 *  解决了Future取消后引起的缓存污染问题
 * @author xuexiaolei
 * @version 2017年10月14日
 */
public class Memoizer4<A, V> implements Computable<A, V> {
    private final Map<A, Future<V>> cache = new ConcurrentHashMap<>();
    private final Computable<A, V> c;//用来计算的内容，假定会浪费很长时间

    public Memoizer4(Computable<A, V> c) {
        this.c = c;
    }

    @Override public V compute(final A arg) throws InterruptedException {
        Future<V> result = cache.get(arg);
        if (result == null){
            FutureTask<V> ft = new FutureTask<V>(new Callable<V>() {
                @Override public V call() throws Exception {
                    return c.compute(arg);
                }
            });
            result = cache.putIfAbsent(arg, result);
            if (result == null) { result = ft; ft.run(); }
        }
        try {
            return result.get();
        } catch (CancellationException e){
            cache.remove(arg, result);
        } catch (ExecutionException e) {
            throw LaunderThrowable.launderThrowable(e.getCause());
        }
        return null;
    }
}
